/*
 * Parser.scala
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.marverse.language

trait Parser[-T, +R] {
  def parse[S <: T](in: Stream[S]): ParseResult[S, R]
  def leftMost: Parser[_ >: T, _]
  def rightMost: Parser[_ >: T, _]

  def :=[Q] (value: Q) = new ConstParser(this, value)
  def *[S <: T, Q >: R](delim: Parser[S, Q]) =
    new RepParser(this, delim, 0, 0)
  def *[S <: T, Q >: R](delim: Parser[S, Q], min: Int) =
    new RepParser(this, delim, min, 0)
  def *[S <: T, Q >: R](delim: Parser[S, Q], min: Int, max: Int) =
    new RepParser(this, delim, min, max)
  def ?() =
    new RepParser(this, ErrorParser, 0, 1)
  def ^^[S <: T, B](transform: (R) => B): Parser[S, B] =
    new TransformParser(this, transform)
}

/**
 * A terminal parser does not return a result.
 */
class TerminalParser[T](val terminal: T) extends Parser[T, Nothing] {
  override def parse[S <: T](in: Stream[S]): ParseResult[S, Nothing] =
    if (in.isEmpty || in.first != terminal)
      Failure
    else
      SuccessOmit(in.drop(1))

  override def leftMost = this
  override def rightMost = this
  override def toString = terminal.toString
}

trait TokenParser[-T, +R] extends Parser[T, R] {
  def parseToken(token: T): Option[R]
  final override def parse[S <: T](in: Stream[S]): ParseResult[S, R] =
    if (in.isEmpty)
      Failure
    else
      parseToken(in.first) match {
        case Some(r) => Success(in.drop(1), r)
        case None => Failure
      }
  override def leftMost = this
  override def rightMost = this
}

object ErrorParser extends Parser[Any, Nothing] {
  override def parse[S](in: Stream[S]) = Failure
  override def leftMost = this
  override def rightMost = this
}

object Parser {
  
  def rep[T, R](inner: Parser[_ >: T, R], 
                delim: Parser[_ >: T, R],
                min: Int): RepParser[T, R] =
    rep(inner, delim, min, 0)
  def rep[T, R](inner: Parser[_ >: T, R],
                delim: Parser[_ >: T, R]): RepParser[T, R] =
    rep(inner, delim, 0, 0)
  def opt[T, R](inner: Parser[_ >: T, R]): RepParser[T, R] =
    rep(inner, ErrorParser, 0, 1)
  def rep[T, R](inner: Parser[_ >: T, R],
                delim: Parser[_ >: T, R],
                min: Int,
                max: Int): RepParser[T, R] =
    new RepParser(inner, delim, min, max)
  
  def any1[T] = new TokenParser[T, T] {
    def parseToken(token: T) = Some(token)
  }
  
  implicit def parser2seq[T, R](parser: Parser[T, R]): SeqParser[T, R] =
    new SeqParser[T, R](Seq(parser))
  
  def t[T](terminal: T) =
    new TerminalParser[T](terminal)
}